package system.impl;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;

public class CommandLineClient extends Client {

	public Integer timeoutInterval;
	private InputStream inputStream;


	public CommandLineClient(CommandLineClientNavigator navigator, InputStream in, OutputStream out, Integer timeoutInterval) {
		super(navigator);
		this.inputStream = in;
		this.in = new Scanner(in);
		this.out = new PrintStream(out);
		this.timeoutInterval = timeoutInterval;
	}


	public CommandLineClient(CommandLineClientNavigator navigator) {
		this(navigator, System.in, System.out, 60);
	}


	protected Scanner in;
	protected PrintStream out;

	
	private String prompt = "";

	public void setPrompt(String string) {
		this.prompt = string;
	}
	
	protected void prompt() {
		out.print(prompt);		
	}


	@Override
	public String getCommand() {
		if(in == null) {
			out.println("Exiting");
			return null;
		}
		prompt();
		if(!in.hasNextLine())
			return null;
		return in.nextLine().trim();
	}

	
	@Override
	public void exit() {
		try {
			inputStream.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace(out);
		}
		if(in != null)
			in.close();
		in = null;
	}

	@Override
	public void gotResult(Command command) {
		out.println( " < " + new PrettyPrintingMap<String,Object>(command.getReturnMap()));
	}

	public void setInputStream(InputStream in2) {
		this.in = new Scanner(in2);
	}

	public void setOutputStream(OutputStream out2) {
		this.out = new PrintStream(out2);
	}

	public void println(String line) {
		out.println(line);
	}
	

	public class PrettyPrintingMap<K, V> {
		
		public static final String tab = "  ";
		
	    private Map<K, V> map;

	    public PrettyPrintingMap(Map<K, V> map) {
	        this.map = map;
	    }

	     @Override
		public String toString() {
	        Integer indent = 0;
	        
	        return toStringIndent(indent);
	    }

		private String toStringIndent(Integer indent) {
	         Iterator<Entry<K,V>> i = map.entrySet().iterator();
	         if (! i.hasNext())
	            return "{}";
	         
	        StringBuilder sb = new StringBuilder();
	        //sb.append('\n');
	        sb.append('{');
	        
	        indent++;
	        for (;;) {
	        	sb.append('\n');
	        	for(int n = 0; n < indent; n++)
	        		sb.append(tab);
	            Entry<K,V> e = i.next();
	            K key = e.getKey();
	            V value = e.getValue();
	            Object val = null;
	            if(value instanceof Map)
	            	val = new PrettyPrintingMap<String,Object>((Map)value);
	            else
	            	val = value;
	            sb.append(key   == this ? "(this Map)" : key);
	            sb.append('=');
	            if(val instanceof PrettyPrintingMap)
	            	sb.append(value == this ? "(this Map)" : ((PrettyPrintingMap)val).toStringIndent(indent));	            	
	            else
	            	sb.append(value == this ? "(this Map)" : value);
	            if (! i.hasNext()) {
	            	sb.append('\n');
	            	indent--;
		        	for(int n = 0; n < indent; n++)
		        		sb.append(tab);
	                return sb.append('}').toString();
	            }
	            sb.append(", ");
	        }

		}
	}

	

}
